#undef BLEND
#undef BLENDSTRETCH
#undef GETPIXEL
#undef BLENDPIXEL
#undef PIXEL_BYTES

#define BLEND MAKE_BLEND(BLEND_MODE, PIXEL_BITS, , )
#define BLENDSTRETCH MAKE_BLEND(BLEND_MODE, PIXEL_BITS, Stretch, )
#define GETPIXEL MAKE_GETPIXEL(PIXEL_BITS)
#define BLENDPIXEL MAKE_BLENDPIXEL(BLEND_MODE, )
#define PIXEL_BYTES (PIXEL_BITS >> 3)

#undef PIXEL
#if PIXEL_BITS == 8
#define PIXEL BYTE
#elif PIXEL_BITS == 24
#define PIXEL xRGB
#elif PIXEL_BITS == 32
#define PIXEL xARGB
#else
#error "unknow PIXEL_BITS"
#endif

BOOL BLEND(PBITMAP lpbDst, PBITMAPEX lpbSrc)
{
    LPBYTE lpScanSrc = (LPBYTE)lpbSrc->bmBits;
    LPBYTE lpScanDst = (LPBYTE)lpbDst->bmBits;
    for (int j = lpbDst->bmHeight; j > 0; --j)
    {
        PBYTE lpPixelSrc = lpScanSrc;
        LPXARGB lpPixelDst = (LPXARGB)lpScanDst;
        for (int i = lpbDst->bmWidth; i > 0; --i)
        {
            xARGB src = GETPIXEL(lpbSrc, lpPixelSrc);
            BLENDPIXEL(lpPixelDst, src);
            lpPixelSrc += PIXEL_BYTES;
            lpPixelDst++;
        }
        lpScanSrc += lpbSrc->bmWidthBytes;
        lpScanDst += lpbDst->bmWidthBytes;
    }
    return TRUE;
}

BOOL BLENDSTRETCH(PBITMAP lpbDst, PBITMAPEX lpbSrc)
{
    LPBYTE lpScanDst = (LPBYTE)lpbDst->bmBits;
    DWORD xrIntFloat16 = (lpbSrc->bmWidth << 16) / lpbDst->bmWidth;
    DWORD yrIntFloat16 = (lpbSrc->bmHeight << 16) / lpbDst->bmHeight;
    DWORD srcy16 = 0;
    for (int j = 0; j < lpbDst->bmHeight; ++j)
    {
        PBYTE lpScanSrc = (LPBYTE)lpbSrc->bmBits + lpbSrc->bmWidthBytes * (srcy16 >> 16);
        DWORD srcx16 = 0;
        LPXARGB lpPixelDst = (LPXARGB)lpScanDst;
        for (int i = 0; i < lpbDst->bmWidth; ++i)
        {
            xARGB src = GETPIXEL(lpbSrc, lpScanSrc + (srcx16 >> 16) * PIXEL_BYTES);
            BLENDPIXEL(lpPixelDst, src);
            srcx16 += xrIntFloat16;
            lpPixelDst++;
        }
        srcy16 += yrIntFloat16;
        lpScanDst += lpbDst->bmWidthBytes;
    }
    return TRUE;
}

BOOL BLENDSTRETCH(PBITMAP lpbDst, PBITMAPEX lpbSrc, LPCSIZE lpszDst, LPCRECT lprcClipped)
{
    LPBYTE lpScanDst = (LPBYTE)lpbDst->bmBits;
    DWORD xrIntFloat16 = (lpbSrc->bmWidth << 16) / lpszDst->cx;
    DWORD yrIntFloat16 = (lpbSrc->bmHeight << 16) / lpszDst->cy;
    DWORD srcy16 = (DWORD)(lprcClipped->top * yrIntFloat16);
    for (int j = 0; j < lpbDst->bmHeight; ++j)
    {
        PBYTE lpScanSrc = (LPBYTE)lpbSrc->bmBits + lpbSrc->bmWidthBytes * (srcy16 >> 16);
        DWORD srcx16 = (DWORD)(lprcClipped->left * xrIntFloat16);
        LPXARGB lpPixelDst = (LPXARGB)lpScanDst;
        for (int i = 0; i < lpbDst->bmWidth; ++i)
        {
            xARGB src = GETPIXEL(lpbSrc, lpScanSrc + (srcx16 >> 16) * PIXEL_BYTES);
            BLENDPIXEL(lpPixelDst, src);
            srcx16 += xrIntFloat16;
            lpPixelDst++;
        }
        srcy16 += yrIntFloat16;
        lpScanDst += lpbDst->bmWidthBytes;
    }
    return TRUE;
}